package models;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import models.writers.TransactionListWriter;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
import play.db.jpa.Model;

@Entity
public class BankStatement extends Model {

    public String label;
    public BigDecimal balance;
    public Date begin;
    public Date end;
    @OneToOne(cascade = CascadeType.ALL)
    public HsbcCreditStatementExtraInfo hsbcCreditStatementExtraInfo;

    @ManyToOne
    public Account account;

    @OneToMany(mappedBy = "statement", cascade = CascadeType.ALL)
    public List<Transaction> transactions;

    public BankStatement(Account account, List<Transaction> transactions, BigDecimal balance, Date begin, Date end) {
        this.transactions = transactions;
        this.balance = balance;
        this.begin = begin;
        this.end = end;
        this.account = account;
    }

    public BankStatement(List<Transaction> transactions) {
        this.transactions = transactions;
        this.balance = calculateTotal(transactions);
        this.begin = getBeginDate(transactions);
        this.end = getEndDate(transactions);
    }

    public static BigDecimal calculateTotal(List<Transaction> transactions) {
        BigDecimal total = new BigDecimal(0);

        for (Transaction transaction : transactions) {
            if (transaction.amount != null) {
                total = total.add(transaction.amount);
            }
        }
        return total;
    }

    public static Date getBeginDate(List<Transaction> transactions) {
        if (transactions.size() == 0) {
            return null;
        }
        Transaction firstTransaction = Collections.min(transactions, new Comparator<Transaction>() {
            public int compare(Transaction o1, Transaction o2) {

                return o1.date.compareTo(o2.date);
            }
        });
        return firstTransaction.date;
    }

    public static Date getEndDate(List<Transaction> transactions) {
        if (transactions.size() == 0) {
            return null;
        }
        Transaction firstTransaction = Collections.max(transactions, new Comparator<Transaction>() {
            public int compare(Transaction o1, Transaction o2) {

                return o1.date.compareTo(o2.date);
            }
        });
        return firstTransaction.date;
    }

    @Override
    public String toString() {
        TransactionListWriter writer = new TransactionListWriter(transactions);

        String header = getHeader();
        String transactionsCsv = writer.writeToString();
        return header + "\n" + transactionsCsv;
    }

    private String getHeader() {
        if (account != null) {
            return account.toString();
        } else {
            return "no account\n";
        }
    }

    public void fixBasicDataInAllTransactions() {
        final Account thisAccount = account;
        final BankStatement thisStatement = this;
        CollectionUtils.forAllDo(transactions, new Closure() {
            public void execute(Object o) {
                Transaction transaction = (Transaction) o;
                transaction.account = thisAccount;
                transaction.statement = thisStatement;
            }
        });
    }
}
